home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / gnu / glibc108.zip / glibc108 / time / __tzset.c next >
C/C++ Source or Header  |  1993-12-14  |  12KB  |  472 lines

  1. /* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
  2. This file is part of the GNU C Library.
  3.  
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Library General Public License as
  6. published by the Free Software Foundation; either version 2 of the
  7. License, or (at your option) any later version.
  8.  
  9. The GNU C Library is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  12. Library General Public License for more details.
  13.  
  14. You should have received a copy of the GNU Library General Public
  15. License along with the GNU C Library; see the file COPYING.LIB.  If
  16. not, write to the Free Software Foundation, Inc., 675 Mass Ave,
  17. Cambridge, MA 02139, USA.  */
  18.  
  19. #include <ansidecl.h>
  20. #include <localeinfo.h>
  21. #include <ctype.h>
  22. #include <stddef.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <time.h>
  27.  
  28. /* Defined in mktime.c.  */
  29. extern CONST unsigned short int __mon_lengths[2][12];
  30.  
  31. #define NOID
  32. #include "tzfile.h"
  33.  
  34. extern int __use_tzfile;
  35. extern void EXFUN(__tzfile_read, (CONST char *file));
  36. extern void EXFUN(__tzfile_default, (char *std AND char *dst AND
  37.                      long int stdoff AND long int dstoff));
  38. extern int EXFUN(__tzfile_compute, (time_t, struct tm));
  39.  
  40. #ifndef    HAVE_GNU_LD
  41. #define    __tzname    tzname
  42. #define    __daylight    daylight
  43. #define    __timezone    timezone
  44. #endif
  45.  
  46. char *__tzname[2] = { (char *) "GMT", (char *) "GMT" };
  47. int __daylight = 0;
  48. long int __timezone = 0L;
  49.  
  50.  
  51. #define    min(a, b)    ((a) < (b) ? (a) : (b))
  52. #define    max(a, b)    ((a) > (b) ? (a) : (b))
  53. #define    sign(x)        ((x) < 0 ? -1 : 1)
  54.  
  55.  
  56. /* This structure contains all the information about a
  57.    timezone given in the POSIX standard TZ envariable.  */
  58. typedef struct
  59.   {
  60.     char *name;
  61.  
  62.     /* When to change.  */
  63.     enum { J0, J1, M } type;    /* Interpretation of:  */
  64.     unsigned short int m, n, d;    /* Month, week, day.  */
  65.     unsigned int secs;        /* Time of day.  */
  66.  
  67.     long int offset;        /* Seconds east of GMT (west if < 0).  */
  68.  
  69.     /* We cache the computed time of change for a
  70.        given year so we don't have to recompute it.  */
  71.     time_t change;    /* When to change to this zone.  */
  72.     int computed_for;    /* Year above is computed for.  */
  73.   } tz_rule;
  74.  
  75. /* tz_rules[0] is standard, tz_rules[1] is daylight.  */
  76. static tz_rule tz_rules[2];
  77.  
  78. int __tzset_run = 0;
  79.  
  80. /* Interpret the TZ envariable.  */
  81. void
  82. DEFUN_VOID(__tzset)
  83. {
  84.   register CONST char *tz;
  85.   register size_t l;
  86.   unsigned short int hh, mm, ss;
  87.   unsigned short int whichrule;
  88.  
  89.   /* Free old storage.  */
  90.   if (tz_rules[0].name != NULL && *tz_rules[0].name != '\0')
  91.     free((PTR) tz_rules[0].name);
  92.   if (tz_rules[1].name != NULL && *tz_rules[1].name != '\0' &&
  93.       tz_rules[1].name != tz_rules[0].name)
  94.     free((PTR) tz_rules[1].name);
  95.  
  96.   tz = getenv("TZ");
  97.  
  98.   if (tz != NULL && *tz == ':')
  99.     {
  100.       __tzfile_read(tz + 1);
  101.       if (__use_tzfile)
  102.     {
  103.       __tzset_run = 1;
  104.       return;
  105.     }
  106.       else
  107.     tz = NULL;
  108.     }
  109.  
  110.   if (tz == NULL || *tz == '\0')
  111.     tz = _time_info->tz;
  112.   if (tz == NULL || *tz == '\0')
  113.     {
  114.       __tzfile_read((char *) NULL);
  115.       if (!__use_tzfile)
  116.     {
  117.       size_t len = strlen(_time_info->ut0) + 1;
  118.       tz_rules[0].name = (char *) malloc(len);
  119.       if (tz_rules[0].name == NULL)
  120.         return;
  121.       tz_rules[1].name = (char *) malloc(len);
  122.       if (tz_rules[1].name == NULL)
  123.         return;
  124.       memcpy((PTR) tz_rules[0].name, _time_info->ut0, len);
  125.       memcpy((PTR) tz_rules[1].name, _time_info->ut0, len);
  126.       tz_rules[0].type = tz_rules[1].type = J0;
  127.       tz_rules[0].m = tz_rules[0].n = tz_rules[0].d = 0;
  128.       tz_rules[1].m = tz_rules[1].n = tz_rules[1].d = 0;
  129.       tz_rules[0].secs = tz_rules[1].secs = 0;
  130.       tz_rules[0].offset = tz_rules[1].offset = 0L;
  131.       tz_rules[0].change = tz_rules[1].change = (time_t) -1;
  132.       tz_rules[0].computed_for = tz_rules[1].computed_for = 0;
  133.     }
  134.       __tzset_run = 1;
  135.       return;
  136.     }
  137.  
  138.   /* Get the standard timezone name.  */
  139.   tz_rules[0].name = (char *) malloc(strlen(tz) + 1);
  140.   if (tz_rules[0].name == NULL)
  141.     return;
  142.  
  143.   if (sscanf(tz, "%[^0-9,+-]", tz_rules[0].name) != 1 ||
  144.       (l = strlen(tz_rules[0].name)) < 3)
  145.     return;
  146.  
  147.   tz_rules[0].name = (char *) realloc((PTR) tz_rules[0].name, l + 1);
  148.   if (tz_rules[0].name == NULL)
  149.     return;
  150.  
  151.   tz += l;
  152.  
  153.   /* Figure out the standard offset from GMT.  */
  154.   if (*tz == '\0' || (*tz != '+' && *tz != '-' && !isdigit(*tz)))
  155.     return;
  156.  
  157.   if (*tz == '-' || *tz == '+')
  158.     tz_rules[0].offset = *tz++ == '-' ? 1L : -1L;
  159.   else
  160.     tz_rules[0].offset = -1L;
  161.   switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
  162.     {
  163.     default:
  164.       return;
  165.     case 1:
  166.       mm = 0;
  167.     case 2:
  168.       ss = 0;
  169.     case 3:
  170.       break;
  171.     }
  172.   tz_rules[0].offset *= (min(ss, 59) + (min(mm, 59) * 60) +
  173.              (min(hh, 12) * 60 * 60));
  174.  
  175.   for (l = 0; l < 3; ++l)
  176.     {
  177.       while (isdigit(*tz))
  178.     ++tz;
  179.       if (l < 2 && *tz == ':')
  180.     ++tz;
  181.     }
  182.  
  183.   /* Get the DST timezone name (if any).  */
  184.   if (*tz == '\0')
  185.     tz_rules[1].name = (char *) "";
  186.   else
  187.     {
  188.       tz_rules[1].name = (char *) malloc(strlen(tz) + 1);
  189.       if (tz_rules[1].name == NULL)
  190.     return;
  191.       if (sscanf(tz, "%[^0-9,+-]", tz_rules[1].name) != 1 ||
  192.       (l = strlen(tz_rules[1].name)) < 3)
  193.     return;
  194.       tz_rules[1].name = (char *) realloc((PTR) tz_rules[1].name, l + 1);
  195.       if (tz_rules[1].name == NULL)
  196.     return;
  197.     }
  198.  
  199.   tz += l;
  200.  
  201.   /* Figure out the DST offset from GMT.  */
  202.   if (*tz == '-' || *tz == '+')
  203.     tz_rules[1].offset = *tz++ == '-' ? 1L : -1L;
  204.   else
  205.     tz_rules[1].offset = -1L;
  206.  
  207.   switch (sscanf (tz, "%hu:%hu:%hu", &hh, &mm, &ss))
  208.     {
  209.     default:
  210.       /* Default to one hour later than standard time.  */
  211.       tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
  212.       break;
  213.  
  214.     case 1:
  215.       mm = 0;
  216.     case 2:
  217.       ss = 0;
  218.     case 3:
  219.       tz_rules[1].offset *= (min(ss, 59) + (min(mm, 59) * 60) +
  220.                  (min(hh, 12) * (60 * 60)));
  221.       break;
  222.     }
  223.   for (l = 0; l < 3; ++l)
  224.     {
  225.       while (isdigit(*tz))
  226.     ++tz;
  227.       if (l < 2 && *tz == ':')
  228.     ++tz;
  229.     }
  230.  
  231.   /* If no standard or DST offset was given, default to GMT
  232.      for standard and one hour later than standard for DST.  */
  233.   if (*tz_rules[0].name == '\0')
  234.     tz_rules[0].offset = 0L;
  235.   if (*tz_rules[1].name == '\0')
  236.     tz_rules[1].offset = tz_rules[0].offset + (60 * 60);
  237.  
  238.   if (*tz == '\0' || (tz[0] == ',' && tz[1] == '\0'))
  239.     {
  240.       /* There is no rule.  See if there is a default rule file.  */
  241.       __tzfile_default (tz_rules[0].name, tz_rules[1].name,
  242.             tz_rules[0].offset, tz_rules[1].offset);
  243.       if (__use_tzfile)
  244.     {
  245.       __tzset_run = 1;
  246.       return;
  247.     }
  248.     }
  249.  
  250.   /* Figure out the standard <-> DST rules.  */
  251.   for (whichrule = 0; whichrule < 2; ++whichrule)
  252.     {
  253.       register tz_rule *tzr = &tz_rules[whichrule];
  254.       
  255.       if (*tz != '\0' && *tz == ',')
  256.     {
  257.       ++tz;
  258.       if (*tz == '\0')
  259.         return;
  260.     }
  261.       
  262.       /* Get the date of the change.  */
  263.       if (*tz == 'J' || isdigit(*tz))
  264.     {
  265.       char *end;
  266.       tzr->type = *tz == 'J' ? J1 : J0;
  267.       if (tzr->type == J1 && !isdigit(*++tz))
  268.         return;
  269.       tzr->d = (unsigned short int) strtoul(tz, &end, 10);
  270.       if (end == tz || tzr->d > 365)
  271.         return;
  272.       else if (tzr->type == J1 && tzr->d == 0)
  273.         return;
  274.       tz = end;
  275.     }
  276.       else if (*tz == 'M')
  277.     {
  278.       int n;
  279.       tzr->type = M;
  280.       if (sscanf (tz, "M%hu.%hu.%hu%n",
  281.               &tzr->m, &tzr->n, &tzr->d, &n) != 3 ||
  282.           tzr->m < 1 || tzr->m > 12 ||
  283.           tzr->n < 1 || tzr->n > 5 || tzr->d > 6)
  284.         return;
  285.       tz += n;
  286.     }
  287.       else if (*tz == '\0')
  288.     {
  289.       /* United States Federal Law, the equivalent of "M4.1.0,M10.5.0".  */
  290.       tzr->type = M;
  291.       if (tzr == &tz_rules[0])
  292.         {
  293.           tzr->m = 4;
  294.           tzr->n = 1;
  295.           tzr->d = 0;
  296.         }
  297.       else
  298.         {
  299.           tzr->m = 10;
  300.           tzr->n = 5;
  301.           tzr->d = 0;
  302.         }
  303.     }
  304.       else
  305.     return;
  306.       
  307.       if (*tz != '\0' && *tz != '/' && *tz != ',')
  308.     return;
  309.       else if (*tz == '/')
  310.     {
  311.       /* Get the time of day of the change.  */
  312.       ++tz;
  313.       if (*tz == '\0')
  314.         return;
  315.       switch (sscanf(tz, "%hu:%hu:%hu", &hh, &mm, &ss))
  316.         {
  317.         default:
  318.           return;
  319.         case 1:
  320.           mm = 0;
  321.         case 2:
  322.           ss = 0;
  323.         case 3:
  324.           break;
  325.         }
  326.       for (l = 0; l < 3; ++l)
  327.         {
  328.           while (isdigit(*tz))
  329.         ++tz;
  330.           if (l < 2 && *tz == ':')
  331.         ++tz;
  332.         }
  333.       tzr->secs = (hh * 60 * 60) + (mm * 60) + ss;
  334.     }
  335.       else
  336.     /* Default to 2:00 AM.  */
  337.     tzr->secs = 2 * 60 * 60;
  338.  
  339.       tzr->computed_for = -1;
  340.     }
  341.  
  342.   __tzset_run = 1;
  343. }
  344.  
  345. /* Maximum length of a timezone name.  __tz_compute keeps this up to date
  346.    (never decreasing it) when ! __use_tzfile.
  347.    tzfile.c keeps it up to date when __use_tzfile.  */
  348. long int __tzname_cur_max;
  349.  
  350. long int
  351. DEFUN_VOID(__tzname_max)
  352. {
  353.   if (! __tzset_run)
  354.     __tzset ();
  355.  
  356.   return __tzname_cur_max;
  357. }
  358.  
  359. /* Figure out the exact time (as a time_t) in YEAR
  360.    when the change described by RULE will occur and
  361.    put it in RULE->change, saving YEAR in RULE->computed_for.
  362.    Return nonzero if successful, zero on failure.  */
  363. static int
  364. DEFUN(compute_change, (rule, year), tz_rule *rule AND int year)
  365. {
  366.   register time_t t;
  367.   int y;
  368.  
  369.   if (year != -1 && rule->computed_for == year)
  370.     /* Operations on times in 1969 will be slower.  Oh well.  */
  371.     return 1;
  372.      
  373.   /* First set T to January 1st, 0:00:00 GMT in YEAR.  */
  374.   t = 0;
  375.   for (y = 1970; y < year; ++y)
  376.     t += SECSPERDAY * (__isleap (y) ? 366 : 365);
  377.  
  378.   switch (rule->type)
  379.     {
  380.     case J1:
  381.       /* Jn - Julian day, 1 == January 1, 60 == March 1 even in leap years.
  382.      In non-leap years, or if the day number is 59 or less, just
  383.      add SECSPERDAY times the day number-1 to the time of
  384.      January 1, midnight, to get the day.  */
  385.       t += (rule->d - 1) * SECSPERDAY;
  386.       if (rule->d >= 60 && __isleap (year))
  387.     t += SECSPERDAY;
  388.       break;
  389.  
  390.     case J0:
  391.       /* n - Day of year.
  392.      Just add SECSPERDAY times the day number to the time of Jan 1st.  */
  393.       t += rule->d * SECSPERDAY;
  394.       break;
  395.  
  396.     case M:
  397.       /* Mm.n.d - Nth "Dth day" of month M.  */
  398.       {
  399.     register int i, d, m1, yy0, yy1, yy2, dow;
  400.  
  401.     /* First add SECSPERDAY for each day in months before M.  */
  402.     for (i = 0; i < rule->m - 1; ++i)
  403.       t += __mon_lengths[__isleap (year)][i] * SECSPERDAY;
  404.  
  405.     /* Use Zeller's Congruence to get day-of-week of first day of month. */
  406.     m1 = (rule->m + 9) % 12 + 1;
  407.     yy0 = (rule->m <= 2) ? (year - 1) : year;
  408.     yy1 = yy0 / 100;
  409.     yy2 = yy0 % 100;
  410.     dow = ((26 * m1 - 2) / 10 + 1 + yy2 + yy2 / 4 + yy1 / 4 - 2 * yy1) % 7;
  411.     if (dow < 0)
  412.       dow += 7;
  413.  
  414.     /* DOW is the day-of-week of the first day of the month.  Get the
  415.        day-of-month (zero-origin) of the first DOW day of the month.  */
  416.     d = rule->d - dow;
  417.     if (d < 0)
  418.       d += 7;
  419.     for (i = 1; i < rule->n; ++i)
  420.       {
  421.         if (d + 7 >= __mon_lengths[__isleap (year)][rule->m - 1])
  422.           break;
  423.         d += 7;
  424.       }
  425.  
  426.     /* D is the day-of-month (zero-origin) of the day we want.  */
  427.     t += d * SECSPERDAY;
  428.       }
  429.       break;
  430.     }
  431.  
  432.   /* T is now the Epoch-relative time of 0:00:00 GMT on the day we want.
  433.      Just add the time of day and local offset from GMT, and we're done.  */
  434.  
  435.   rule->change = t + rule->offset + rule->secs;
  436.   rule->computed_for = year;
  437.   return 1;
  438. }
  439.  
  440.  
  441. /* Figure out the correct timezone for *TIMER and TM (which must be the same)
  442.    and set `__tzname', `__timezone', and `__daylight' accordingly.
  443.    Return nonzero on success, zero on failure.  */
  444. int
  445. DEFUN(__tz_compute, (timer, tm),
  446.       time_t timer AND const struct tm *tm)
  447. {
  448.   if (! __tzset_run)
  449.     __tzset ();
  450.  
  451.   if (! compute_change (&tz_rules[0], 1900 + tm->tm_year) ||
  452.       ! compute_change (&tz_rules[1], 1900 + tm->tm_year))
  453.     return 0;
  454.  
  455.   __daylight = timer >= tz_rules[0].change && timer < tz_rules[1].change;
  456.   __timezone = tz_rules[__daylight ? 1 : 0].offset;
  457.   __tzname[0] = (char *) tz_rules[0].name;
  458.   __tzname[1] = (char *) tz_rules[1].name;
  459.  
  460.   {
  461.     /* Keep __tzname_cur_max up to date.  */
  462.     size_t len0 = strlen (__tzname[0]);
  463.     size_t len1 = strlen (__tzname[1]);
  464.     if (len0 > __tzname_cur_max)
  465.       __tzname_cur_max = len0;
  466.     if (len1 > __tzname_cur_max)
  467.       __tzname_cur_max = len1;
  468.   }
  469.  
  470.   return 1;
  471. }
  472.